package etl;
import java.sql.*;
import backend.*;

public class Transformer {
	
	private Warehouse wh;
	
	public Transformer(Warehouse whIn)
	{
		wh = whIn;
	}
	
	public void transform(ReadingData data) throws SQLException {
		
		// Fact for later filling
		Fact f = null;
		
		// Convert timestamp to DateTime for storage
		DateTime ts = wh.getDateTimeFromDate(data.timestamp);
		
		// Look for the Location in the warehouse
		Location l = wh.getLocation(data.locationId);
		
		// If this is the first reading on the location
		if (l == null)
		{
			l = new Location(
					data.locationId,
					data.countryCode,
					data.airportCode,
					data.readerLocation,
					Location.getType(data.readerLocationType));
			
			wh.insertLocation(l);
		}
		
		// Look for the Bag in the warehouse
		Bag b = wh.getBagByLicensePlate(data.licensePlate);
		boolean bagExisted = true;
		
		// If this is the first reading of the bag
		if (b == null)
		{
			bagExisted = false;
			
			b = new Bag(-1, data.licensePlate, data.originatingAirport, -1, createRouteLegArray(data));
			
			wh.insertBag(b);
		}
		
		// If the bag already existed
		if (bagExisted)
		{
			// Find last added Fact of the bag, see if we need to update it or add a new one
			Fact last = wh.getLatestFactByBag(b.getId());
			
			// If this row has more route legs than the Bag in the warehouse, update the warehouse
			if (data.routeLegs.length > b.getBagRoute().length)
			{
				b.setOriginatingAirport(data.originatingAirport);
				b.setBagRoute(wh, createRouteLegArray(data));
			}
			
			// Was the last Fact in the same airport as this reading?
			if (last.getLocation().isSameAirport(l))
			{
				// Extend the last fact and update it in the database
				last.setDuration((int)last.getDateTime().getDurationUntil(ts));
				wh.updateFactDuration(last);
				
				// Was this reading in a different location than the last one?
				if (!last.getLocation().equals(l))
				{
					// Create a new fact with duration 0, that is not lost
					f = new Fact(wh, -1, ts.getTimeId(), ts.getDateId(), b.getId(), l.getId(), 0, last.getStatus());
				}
			}
			// Has the bag reached a new airport?
			else
			{
				// Set the lost status depending on whether the bag was previously lost
				boolean lost = last.getStatus();
				
				// If it was not previously lost
				if (!lost)
				{
					// Check whether the bag is now lost
					RouteLeg[] r = b.getBagRoute();
					for (int i=0; i<r.length; i++)
					{
						if (r[i].getDestination() == last.getLocation().getAirport())
						{
							lost = r[i+1].getDestination() != data.airportCode;
							break;
						}
					}
				}
				
				// Create a new fact with duration 0, and the proper lost status
				f = new Fact(wh, -1, ts.getTimeId(), ts.getDateId(), b.getId(), l.getId(), 0, lost);
			}
			
		}
		// If we just added the bag
		else
		{
			// Bag is lost unless the current airport is nowhere to be found in the route
			boolean lost = true;
			if (b.getOriginatingAirport().equals(data.airportCode))
			{
				lost = false;
			}
			else
			{
				RouteLeg[] r = b.getBagRoute();
				for (RouteLeg leg : r)
				{
					if (leg.getDestination().equals(data.airportCode))
					{
						lost = false;
						break;
					}
				}
			}
			
			// Add new Fact, set duration to 0, and the proper lost status
			f = new Fact(wh, -1, ts.getTimeId(), ts.getDateId(), b.getId(), l.getId(), 0, lost);
		}
		
		// If a new Fact has been created, add it to the warehouse
		if (f != null)
		{
			wh.insertFact(f);
		}
		
	}

	private RouteLeg[] createRouteLegArray(ReadingData data) {
		RouteLeg[] legs = new RouteLeg[data.numRouteLegs];
		
		for (int i=0; i<legs.length; i++)
		{
			int id = wh.getRouteLegId(data.routeLegs[i].destinationCode, data.routeLegs[i].airlineCode);
			legs[i] = new RouteLeg(id, data.routeLegs[i].destinationCode, data.routeLegs[i].airlineCode, i+1);
		}
		return legs;
	}
	
}
